package logger

import (
	"io"
	"os"
	"runtime"
	"strconv"
	"strings"
	"time"

	"github.com/rs/zerolog"
)

type Level int8

const (
	DebugLevel Level = iota
	InfoLevel
	WarnLevel
	ErrorLevel

	Disabled
)

type logger struct {
	log zerolog.Logger
}

func color_string(str, color string) string {
	return "\x1B[" + color + "m" + str + "\x1B[0m"
}

func ConsoleWriter(NoColor bool) io.Writer {
	zerolog.TimeFieldFormat = time.RFC3339Nano
	io := zerolog.ConsoleWriter{
		Out:        os.Stdout,
		TimeFormat: "150405.000",
		// TimeFormat: "20060102 150405.000",
		NoColor: NoColor,
	}
	io.FormatCaller = func(i interface{}) string {
		if pc, file, line, ok := runtime.Caller(8); ok {
			str_pc := runtime.FuncForPC(pc).Name()
			str_file := file[strings.LastIndexByte(file, '/')+1:]
			str_line := strconv.Itoa(line)
			if io.NoColor {
				return str_pc + " " + str_file + ":" + str_line + " "
			}
			return color_string(str_pc, "3") + " " +
				color_string(str_file, "1") + ":" +
				color_string(str_line, "1;36") + " "
		}
		return " "
	}
	return io
}

func Init() logger {
	log := zerolog.New(ConsoleWriter(false)).
		With().Timestamp().Logger().
		With().Caller().Logger()
	return logger{
		log: log,
	}
}

func (l logger) SetLevel(lvl Level) {
	switch lvl {
	case DebugLevel:
		zerolog.SetGlobalLevel(zerolog.DebugLevel)
	case InfoLevel:
		zerolog.SetGlobalLevel(zerolog.InfoLevel)
	case WarnLevel:
		zerolog.SetGlobalLevel(zerolog.WarnLevel)
	case ErrorLevel:
		zerolog.SetGlobalLevel(zerolog.ErrorLevel)
	case Disabled:
		zerolog.SetGlobalLevel(zerolog.Disabled)
	}
}

func (l logger) Debug(fmt string, v ...interface{}) {
	l.log.Debug().Msgf(fmt, v...)
}
func (l logger) Info(fmt string, v ...interface{}) {
	l.log.Info().Msgf(fmt, v...)
}
func (l logger) Warn(fmt string, v ...interface{}) {
	l.log.Warn().Msgf(fmt, v...)
}
func (l logger) Error(fmt string, v ...interface{}) {
	l.log.Error().Msgf(fmt, v...)
}
